/*  Copyright (c) 2011, Philip Busch <vzxwco@gmail.com>
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *   - Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */


#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "5.h"

static void normalize_input(char *buf, size_t len)
{
	size_t i;

	for (i = 0; i < len; i++)
		if (buf[i] == '\r')
			buf[i] = '\n';
}

static int is_input(nc *n);
static int on_connect(nc *n, size_t len);
static int on_fallback(nc *n, size_t len);

static int is_single_newline(nc *n);
static int on_single_newline(nc *n, size_t len);
static int is_quit(nc *n);
static int on_quit(nc *n, size_t len);

int core_register_callbacks(nc *n)
{
	nc_register_callback(n, &nc_is_connect, &on_connect);
	nc_register_callback(n, &is_single_newline, &on_single_newline);
	nc_register_callback(n, &is_quit, &on_quit);
	nc_register_callback(n, &is_input, &on_fallback);

	return 0;
}

static int is_input(nc *n)
{
	size_t i, nbytes;
	char *buf;

	nbytes = nc_size(n);

	buf = malloc(nbytes);
	if (buf == NULL)
		return -1;

	nc_peak(n, buf, nbytes);
	normalize_input(buf, nbytes);

	for (i = 0; i < nbytes; i++)
		if (buf[i] == '\n') {
			free(buf);
			return i+1;
		}

	free(buf);
	return 0;
}

static int is_single_newline(nc *n)
{
	char c;

	if (nc_peak(n, &c, 1))
		if (c == '\n' || c == '\r')
			return 1;

	return 0;
}

static int on_single_newline(nc *n, size_t len)
{
	char c;

	return nc_recv(n, &c, len);
}

static int is_quit(nc *n)
{
	char buf[4];

	if (nc_peak(n, buf, 4) == 4)
		if (!strncmp(buf, "quit", 4))
			return 4;

	return 0;
}

static int on_quit(nc *n, size_t len)
{
	char buf[4];

	nc_recv(n, buf, len);
	nc_send(n, "Bye.\n", 5);

	return len;
}

static int on_fallback(nc *n, size_t len)
{
	char *buf;

	buf = NULL;

	if (len > 0) {
		buf = malloc(len);
		if (buf == NULL)
			return -1;

		// consume invalid input
		nc_recv(n, buf, len);
		normalize_input(buf, len);
		nc_send(n, "ERROR: ", strlen("ERROR: "));
		nc_send(n, buf, len);
	}

	free(buf);
	return len+1000;
}

static int on_connect(nc *n, size_t len)
{
	char buf[1024];

	if (len) {}

	sprintf(buf, "%s v%s\n", PROG_NAME, PROG_VERSION);

	return nc_send(n, buf, strlen(buf));
}

